%code top{
    #include <iostream>
    #include <assert.h>
    #include "parser.h"
    extern Ast ast;
    int yylex();
    int yyerror( char const * );
}

%code requires {
    #include "Ast.h"
    #include "SymbolTable.h"
    #include "Type.h"
}

%union {
    int itype;
    char* strtype;
    StmtNode* stmttype;
    ExprNode* exprtype;
    Type* type;

}

%start Program
%token <strtype> ID 
%token <itype> INTEGER
%token IF ELSE
%token INT VOID
%token LP RP LB RB SEMICOLON COLON 
%token ADD SUB OR AND LESS ASSIGN GREATER EQ NEQ GEQ LEQ MUL DIV MOD NOT BREAK CONTINUE FOR SELFADD SELFDEC SCAN PRINT
%token COMMA
%token WHILE
%token MAIN

%token RETURN

%nterm <stmttype> Stmts Stmt AssignStmt IfStmt ReturnStmt WhileStmt DeclStmt BlockStmt FuncDef VarDefList VarDef BreakStmt ContinueStmt IOStmt ForStmt AssignS
%nterm <exprtype> Exp AddExp Cond LOrExp PrimaryExp LVal RelExp LAndExp MulExp UnaryExp 
%nterm <type> Type



%precedence THEN
%precedence ELSE
%%
Program
    : 
    /* TODO: 定义程序的语法规则 */
    Stmts {
        ast.setRoot($1);//设置分析树的root
    }
    ;
Stmts
    : 
    /* TODO: 定义语句序列的语法规则 */
    Stmts Stmt{
            SeqNode* node = dynamic_cast<SeqNode*>($1);
            node->addNext(dynamic_cast<StmtNode*>($2));
            $$ = dynamic_cast<StmtNode*>(node);
        }
    |   Stmt{
            SeqNode* node = new SeqNode();
            node->addNext(dynamic_cast<StmtNode*>($1));
            $$ = dynamic_cast<StmtNode*>(node);
        }
    ;
Stmt
    : 
    AssignStmt {$$=$1;}
    | IfStmt {$$=$1;}
    | ReturnStmt {$$=$1;}
    | DeclStmt {$$=$1;}
    | WhileStmt {$$=$1;}
    | BlockStmt {$$=$1;} //块
    | FuncDef {$$=$1;} //函数定义
    | BreakStmt {$$=$1;}
    | ContinueStmt {$$=$1;}
    | IOStmt {$$=$1;}
    | ForStmt {$$=$1;}

    ;
AssignStmt
    :
    /* TODO: 定义赋值语句的语法规则 */
    LVal ASSIGN Exp SEMICOLON {
        // std::cout<<"ASSIGN"<<std::endl;
        $$ = new AssignStmt($1, $3);
    }
    |
    LVal SELFADD SEMICOLON {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());

        $$ = new AssignStmt($1, new BinaryExpr(se, BinaryExpr::ADD, $1, new Constant(new ConstantSymbolEntry(TypeSystem::intType, 1))));
    }
    |
    LVal SELFDEC SEMICOLON {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());

        $$ = new AssignStmt($1, new BinaryExpr(se, BinaryExpr::SUB, $1, new Constant(new ConstantSymbolEntry(TypeSystem::intType, 1))));
    }
    |
    SELFDEC LVal SEMICOLON {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());

        $$ = new AssignStmt($2, new BinaryExpr(se, BinaryExpr::SUB, $2, new Constant(new ConstantSymbolEntry(TypeSystem::intType, 1))));
    }
    |
    SELFADD LVal SEMICOLON {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());

        $$ = new AssignStmt($2, new BinaryExpr(se, BinaryExpr::ADD, $2, new Constant(new ConstantSymbolEntry(TypeSystem::intType, 1))));
    }
    ;



AssignS
    :
    /* TODO: 定义赋值语句的语法规则 */
    LVal ASSIGN Exp {
        // std::cout<<"ASSIGN"<<std::endl;
        $$ = new AssignStmt($1, $3);
    }
    |
    LVal SELFADD {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());

        $$ = new AssignStmt($1, new BinaryExpr(se, BinaryExpr::ADD, $1, new Constant(new ConstantSymbolEntry(TypeSystem::intType, 1))));
    }
    |
    LVal SELFDEC {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());

        $$ = new AssignStmt($1, new BinaryExpr(se, BinaryExpr::SUB, $1, new Constant(new ConstantSymbolEntry(TypeSystem::intType, 1))));
    }
    |
    SELFDEC LVal {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());

        $$ = new AssignStmt($2, new BinaryExpr(se, BinaryExpr::SUB, $2, new Constant(new ConstantSymbolEntry(TypeSystem::intType, 1))));
    }
    |
    SELFADD LVal {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());

        $$ = new AssignStmt($2, new BinaryExpr(se, BinaryExpr::ADD, $2, new Constant(new ConstantSymbolEntry(TypeSystem::intType, 1))));
    }
    |
    Type ID ASSIGN Exp{
        identifiers = new SymbolTable(identifiers);
        // 首先将ID插入符号表中
        Type* type;
        type = TypeSystem::intType;
        SymbolEntry *se;
        se = new IdentifierSymbolEntry(type, $2, identifiers->getLevel());
        identifiers->install($2, se);
        $$ = new DefNode(new Id(se), dynamic_cast<Node*>($4));
    }
    ;


BlockStmt
    :   
    LB
    {identifiers = new SymbolTable(identifiers);}
    Stmts RB
    {
        $$ = new CompoundStmt($3);
        SymbolTable *top = identifiers;
        identifiers = identifiers->getPrev();
        delete top;
    }
    |
    LB
    RB
    {
        $$ = new CompoundStmt(nullptr);
    }
    ;

FuncDef
    :
    Type MAIN LP RP BlockStmt
    {
        Type *funcType;
        funcType = new FunctionType($1,{});
        // 创建 main 函数的符号表条目，返回类型为 int
        SymbolEntry *se = new IdentifierSymbolEntry(funcType, "main", identifiers->getLevel());
        identifiers->install("main", se); // 将 main 函数的符号表条目安装到符号表中
        identifiers = new SymbolTable(identifiers); // 创建 main 函数的符号表
        $$ = new FunctionDef(se, $5);
  
    }
    ;

IfStmt
    :
    /* TODO: 定义条件语句的语法规则 */
    IF LP Cond RP Stmt %prec THEN {//%prec 关键字，将终结符then 的优先级赋给产生式。
        $$ = new IfStmt($3, $5);
    }
    | IF LP Cond RP Stmt ELSE Stmt {
        $$ = new IfElseStmt($3, $5, $7);
    }
    ;

//break 语句
BreakStmt
    :   BREAK SEMICOLON {
            $$ = new BreakStmt();
        }
    ;

//continue 语句
ContinueStmt
    :   CONTINUE SEMICOLON{
            $$ = new ContinueStmt();
        }
    ;


ReturnStmt
    :
    /* TODO: 定义返回语句的语法规则 */
    RETURN Exp SEMICOLON {
        $$ = new ReturnStmt($2);
    }
    | RETURN SEMICOLON {
        $$ = new ReturnStmt();
    }
    ;
Exp
    :
    /* TODO: 定义表达式的语法规则 */
    AddExp {$$ = $1;}
    
    ;
Cond
    :
    /* TODO: 定义条件表达式的语法规则 */
    LOrExp {$$ = $1;}
    
    ;
PrimaryExp
    :
    /* TODO: 定义初级表达式的语法规则 */
    LVal {//左值
        $$ = $1;
    }
    |
    LP Exp RP  {
        $$ = $2;
    }
    |
    INTEGER {
        SymbolEntry *se = new ConstantSymbolEntry(TypeSystem::intType, $1);
        $$ = new Constant(se);
    }
    ;
AddExp
    :
    /* TODO: 定义加法表达式的语法规则 */
    MulExp {
            $$ = $1;
        }
    |   AddExp ADD MulExp {
            SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
            
            $$ = new BinaryExpr(se, BinaryExpr::ADD, $1, $3);
        }
    |   AddExp SUB MulExp {
            SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
            $$ = new BinaryExpr(se, BinaryExpr::SUB, $1, $3);
        }
    ;

// 乘法级表达式
MulExp:
    /* 乘除取模运算 */
    UnaryExp {$$ = $1;}
    |
    MulExp MUL UnaryExp
    {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::MUL, $1, $3);
    }
    |
    MulExp DIV UnaryExp
    {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::DIV, $1, $3);
    }
    |
    MulExp MOD UnaryExp
    {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::MOD, $1, $3);
    }
    ; 

UnaryExp
    :
    ADD  UnaryExp
    {$$ = $2;}
    |
    SUB UnaryExp
    {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::SUB, $2);
    }
    |
    PrimaryExp
    {
        $$ =$1;
    }
    |
    NOT UnaryExp {
            SymbolEntry *tmp = new TemporarySymbolEntry(TypeSystem::boolType, SymbolTable::getLabel());
            $$ = new BinaryExpr(tmp, BinaryExpr::NOT, $2);
        }
    ;




RelExp
    :
    /* TODO: 定义关系表达式的语法规则 */
    AddExp {$$ = $1;}
    |
    //--------------------------逻辑运算
    RelExp LESS AddExp
    {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::LESS, $1, $3);
    }
    |
    RelExp GREATER AddExp
    {
		SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
		$$ = new BinaryExpr(se, BinaryExpr::GREATER, $1, $3);
	}
	|
	RelExp EQ AddExp
	{
		SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
		$$ = new BinaryExpr(se, BinaryExpr::EQ, $1, $3);
	}
	|
	RelExp NEQ AddExp
	{
		SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
		$$ = new BinaryExpr(se, BinaryExpr::NEQ, $1, $3);
	}
	|
	RelExp GEQ AddExp
	{
		SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
		$$ = new BinaryExpr(se, BinaryExpr::GEQ, $1, $3);
	}
	|
	RelExp LEQ AddExp
	{
		SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
		$$ = new BinaryExpr(se, BinaryExpr::LEQ, $1, $3);
	}
    ;
LAndExp
    :
    /* TODO: 定义逻辑与表达式的语法规则 */
    RelExp {$$ = $1;}
    |
    LAndExp AND RelExp
    {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::AND, $1, $3);
    }

    ;
LOrExp
    :
    /* TODO: 定义逻辑或表达式的语法规则 */
    LAndExp {$$ = $1;}
    |
    LOrExp OR LAndExp
    {
        SymbolEntry *se = new TemporarySymbolEntry(TypeSystem::intType, SymbolTable::getLabel());
        $$ = new BinaryExpr(se, BinaryExpr::OR, $1, $3);
    }


    ;
Type
    :
    /* TODO: 定义类型的语法规则 */
    INT {
        $$ = TypeSystem::intType;
    }
    | VOID {
        $$ = TypeSystem::voidType;
    }
    ;

DeclStmt
    :
    /* TODO: 定义声明语句的语法规则 */
    Type VarDefList SEMICOLON {
        $$ = $2;
    }
    ;

VarDefList
    :   VarDefList COMMA VarDef {
            DeclStmt* node = dynamic_cast<DeclStmt*>($1);
            node->addNext(dynamic_cast<DefNode*>($3));
            $$ = node;
        }
    |   VarDef {
            DeclStmt* node = new DeclStmt(true);
            node->addNext(dynamic_cast<DefNode*>($1));
            $$ = node;
        }
    ;

// 变量定义
VarDef
    :   ID {
            // 首先判断是否重定义
            if(identifiers->isRedefine($1)) {
                fprintf(stderr, "identifier %s redefine\n", $1);
                exit(EXIT_FAILURE);
            }
            // 首先将ID插入符号表中
            Type* type;
                type = TypeSystem::intType;
            SymbolEntry *se;
            se = new IdentifierSymbolEntry(type, $1, identifiers->getLevel());
            identifiers->install($1, se);
            $$ = new DefNode(new Id(se), nullptr);
        }
    |   ID ASSIGN Exp {
            // 首先判断是否重定义
            if(identifiers->isRedefine($1)) {
                fprintf(stderr, "identifier %s redefine\n", $1);
                exit(EXIT_FAILURE);
            }
            // 首先将ID插入符号表中
            Type* type;
            type = TypeSystem::intType;
            SymbolEntry *se;
            se = new IdentifierSymbolEntry(type, $1, identifiers->getLevel());
            identifiers->install($1, se);
            $$ = new DefNode(new Id(se), dynamic_cast<Node*>($3));
        }
    ;


/* TODO: 定义其他可能的语法规则 */

LVal//定义变量左值
    : ID {
        SymbolEntry *se;
        se = identifiers->lookup($1);
        if(se == nullptr)
        {
            fprintf(stderr, "identifier \"%s\" is undefined\n", (char*)$1);//此处已检查未定义问题
            delete [](char*)$1;
            assert(se != nullptr);
        }
        $$ = new Id(se);
        delete []$1;
    }
    ;

 
    


WhileStmt //while(cond) stmt
    :
    WHILE LP Cond RP Stmt
    {
        $$=new WhileStmt($3,$5);
    }
    ;

ForStmt
    :
    FOR LP AssignS SEMICOLON Cond SEMICOLON AssignS RP Stmt
    {
        $$=new ForStmt($3,$5,$7,$9);
        identifiers = identifiers->getPrev();
    }
    ;


IOStmt
    :
    SCAN LP ID RP SEMICOLON
    {
        SymbolEntry *se;
        se = identifiers->lookup($3);
        if(se == nullptr)
        {
            fprintf(stderr, "identifier \"%s\" is undefined\n", (char*)$3);//此处已检查未定义问题
            delete [](char*)$3;
            assert(se != nullptr);
        }
        $$ = new IOStmt(IOStmt::SCAN, new Id(se));
        delete []$3;
    }
    | PRINT LP Exp RP SEMICOLON
    {
        $$ = new IOStmt(IOStmt::PRINT, $3);
    }





%%

int yyerror(char const* message)
{
    std::cerr<<message<<std::endl;
    return -1;
}
